import numpy as np
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point, LineString
from pyproj import CRS
import matplotlib.pyplot as plt
from typing import List, Dict, Tuple
import warnings
import json
import mysql.connector
import datetime


# MySQL数据库配置
config = {
    'user': 'root',
    'password': '123456',
    'host': '192.168.124.8',
    'database': 'vanna_ai',
    'port': '3333',
}


class MultiBorderMonitor:
    def __init__(self, border_files: List[str],
                 proximity_threshold: float = 1000,
                 min_proximity_time: float = 300,
                 crossing_buffer: float = 50,
                 crs_epsg: int = 32650):
        """
        初始化多头边境监测分析器
        参数:
            border_files: 边境线GeoJSON文件路径列表
            proximity_threshold: 接近边境的距离阈值(米)
            min_proximity_time: 最小接近时间(秒)
            crossing_buffer: 越境判断的缓冲距离(米)
            crs_epsg: 投影坐标系EPSG代码(默认UTM Zone 50N)
        """
        self.crs = CRS.from_epsg(crs_epsg)
        self.borders = self._load_borders(border_files)
        self.proximity_threshold = proximity_threshold
        self.min_proximity_time = min_proximity_time
        self.crossing_buffer = crossing_buffer

    def _load_borders(self, border_files: List[str]) -> List[LineString]:
        """加载多条边境线数据并转换为投影坐标系"""
        borders = []
        for file in border_files:
            try:
                gdf = gpd.read_file(file)
                if gdf.crs is None:
                    gdf = gdf.set_crs("EPSG:4326")
                gdf = gdf.to_crs(self.crs)
                borders.append(LineString(gdf.geometry))
            except Exception as e:
                warnings.warn(f"加载边境线文件 {file} 失败: {str(e)}")
        return borders

    def _distance_to_borders(self, point: Tuple[float, float]) -> Dict[str, float]:
        """计算点到各条边境线的最短距离(米)"""
        point_geom = Point( point[0], point[1])  # 注意坐标顺序
        point_gdf = gpd.GeoDataFrame(geometry=[point_geom], crs="EPSG:4326")
        point_gdf = point_gdf.to_crs(self.crs)

        distances = {}
        for i, border in enumerate(self.borders):
            distances[f"border_{i}"] = float(border.distance(point_gdf.geometry.iloc[0]))
        return distances

    def _is_crossing_any_border(self, point1: Tuple[float, float], point2: Tuple[float, float]) -> Dict:
        """
        判断两点连线是否跨越任何边境线

        返回:
            {
                "crossed": bool,
                "border_index": int or None,
                "location": (lat, lon) or None
            }
        """
        line = LineString([(point1[1], point1[0]), (point2[1], point2[0])])
        line_gdf = gpd.GeoDataFrame(geometry=[line], crs="EPSG:4326")
        line_gdf = line_gdf.to_crs(self.crs)

        for i, border in enumerate(self.borders):
            buffered_border = border.buffer(self.crossing_buffer)
            if buffered_border.intersects(line_gdf.geometry.iloc[0]):
                intersection = buffered_border.intersection(line_gdf.geometry.iloc[0])
                intersection_gdf = gpd.GeoDataFrame(geometry=[intersection], crs=self.crs)
                intersection_gdf = intersection_gdf.to_crs("EPSG:4326")
                loc = intersection_gdf.geometry.iloc[0].coords[0]
                return {
                    "crossed": True,
                    "border_index": i,
                    "location": (loc[1], loc[0])  # 返回(lat, lon)
                }
        return {"crossed": False, "border_index": None, "location": None}

    def analyze_trajectory(self, trajectory: pd.DataFrame) -> Dict:
        """
        分析轨迹数据相对于多条边境线的行为

        返回:
            {
                "proximity_events": List[dict],
                "crossing_events": List[dict],
                "statistics": dict
            }
        """
        if not isinstance(trajectory, pd.DataFrame):
            raise ValueError("轨迹数据必须是Pandas DataFrame")

        required_columns = ['timestamp', 'latitude', 'longitude']
        if not all(col in trajectory.columns for col in required_columns):
            raise ValueError(f"轨迹数据必须包含列: {required_columns}")

        trajectory = trajectory.copy()
        trajectory['timestamp'] = pd.to_datetime(trajectory['timestamp']*1000,unit='ms')
        trajectory.sort_values('timestamp', inplace=True)

        results = {
            "proximity_events": [],
            "crossing_events": [],
            "statistics": {
                "total_proximity_time": 0,
                "max_proximity_duration": 0,
                "crossing_count": 0,
                "closest_approach": float('inf')
            }
        }

        # 计算到各条边境线的距离
        for i in range(len(self.borders)):
            trajectory[f'distance_to_border_{i}'] = trajectory.apply(
                lambda row: self._distance_to_borders((row['latitude'], row['longitude']))[f'border_{i}'],
                axis=1
            )
        print("检测边境越界事件")
        # 检测越境事件
        prev_crossing_time = None
        for i in range(1, len(trajectory)):
            prev_point = (trajectory.iloc[i - 1]['latitude'], trajectory.iloc[i - 1]['longitude'])
            curr_point = (trajectory.iloc[i]['latitude'], trajectory.iloc[i]['longitude'])

            crossing_result = self._is_crossing_any_border(prev_point, curr_point)
            if crossing_result["crossed"]:
                # 避免重复检测同一越境事件
                is_new_event = True
                if prev_crossing_time and (trajectory.iloc[i]['timestamp'] - prev_crossing_time).total_seconds() < 60:
                    is_new_event = False

                if is_new_event:
                    event = {
                        "time": trajectory.iloc[i]['timestamp'],
                        "border_index": crossing_result["border_index"],
                        "location": crossing_result["location"],
                        "direction": self._get_crossing_direction(prev_point, curr_point,
                                                                  crossing_result["border_index"]),
                        "point_before": prev_point,
                        "point_after": curr_point
                    }
                    results["crossing_events"].append(event)
                    results["statistics"]["crossing_count"] += 1
                    prev_crossing_time = trajectory.iloc[i]['timestamp']

        return results

    def _get_crossing_direction(self, point1: Tuple[float, float], point2: Tuple[float, float],
                                border_index: int) -> str:
        """判断越境方向（入境/出境）"""
        dist1 = self._distance_to_borders(point1)[f'border_{border_index}']
        dist2 = self._distance_to_borders(point2)[f'border_{border_index}']
        return "inbound" if dist2 < dist1 else "outbound"

    def visualize_results(self, trajectory: pd.DataFrame, results: Dict, save_path: str = None):
        """可视化分析结果"""
        fig, ax = plt.subplots(figsize=(15, 10))

        try:
            # 绘制所有边境线
            for i, border in enumerate(self.borders):
                border_gdf = gpd.GeoDataFrame(geometry=[border], crs=self.crs)
                border_gdf = border_gdf.to_crs("EPSG:4326")
                border_gdf.plot(ax=ax, color='red', linewidth=2, label=f'Border {i}')

            # 绘制原始轨迹
            trajectory_gdf = gpd.GeoDataFrame(
                trajectory,
                geometry=gpd.points_from_xy(trajectory.longitude, trajectory.latitude),
                crs="EPSG:4326"
            )
            trajectory_gdf.plot(ax=ax, color='blue', markersize=4, alpha=0.5, label='Trajectory')

            # 标记越境事件
            for event in results["crossing_events"]:
                ax.scatter(
                    event["location"][1], event["location"][0],
                    color='red', s=100, marker='x', linewidths=2,
                    label=f'Crossing Border {event["border_index"]} ({event["direction"]})'
                )

            # 处理图例
            handles, labels = ax.get_legend_handles_labels()
            by_label = dict(zip(labels, handles))
            ax.legend(by_label.values(), by_label.keys())

            plt.title('Multi-Border Proximity and Crossing Analysis')

            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight')
                print(f"可视化结果已保存至: {save_path}")
            else:
                plt.show()

        except Exception as e:
            print(f"可视化过程中发生错误: {e}")
        finally:
            plt.close()


def set_result_to_mysql(reg_id, icao, merged_event):
    direction = "抵近" if merged_event['direction'] == 'inbound' else "远离"
    # print(f"- 时间范围: {merged_event['start_time']} 至 {merged_event['end_time']}, 方向: {direction}")
    # print(f"  起点坐标: {merged_event['start_point']}, 终点坐标: {merged_event['end_point']}")
    connection = mysql.connector.connect(**config)
    cursor = connection.cursor()
    cursor.execute(
        "INSERT INTO territory_infringe_event (reg_id, icao, start_time, end_time, direction, start_point, end_point) VALUES (%s, %s, %s, %s, %s, %s, %s)",
        (reg_id, icao, str(merged_event['start_time']), str(merged_event['end_time']), direction,
         str(merged_event['start_point']), str(merged_event['end_point']))
    )
    connection.commit()



def get_all_aircrafts():
    connection = mysql.connector.connect(**config)
    cursor = connection.cursor()
    cursor.execute("SELECT icao, reg_id FROM military_aircraft where "
                   "type = 'P8' or type = 'RC135' or type = 'P8' or type = 'W135'")
    aircrafts = cursor.fetchall()
    return aircrafts


def get_aircraft_trace(reg_id):
    connection = mysql.connector.connect(**config)
    cursor = connection.cursor()
    cursor.execute("SELECT latitude, longitude, timestamp FROM military_aircraft_trace WHERE reg_id = %s", (reg_id,))
    trace_dict = cursor.fetchall()
    return trace_dict

# 示例用法
if __name__ == "__main__":
    border_files = [
        r"./geojson.geojson",
        r"./曾母暗沙.geojson",
        r"./赤尾屿.geojson",
        r"./钓鱼岛.geojson",
        r"./东沙群岛.geojson",
        r"./黄尾屿.geojson",
        r"./黄岩岛.geojson",
        r"./南沙群岛.geojson",
        r"./彭佳屿.geojson",
        r"./澎湖列岛.geojson",
        r"./台湾.geojson",
        r"./西沙群岛.geojson",
        r"./中沙群岛.geojson"
    ]

    # 创建分析器
    monitor = MultiBorderMonitor(
        border_files=border_files,
        proximity_threshold=100,  # 500000米接近阈值
        min_proximity_time=0,  # 5分钟最小接近时间
        crossing_buffer=150000,  # 100000米越境缓冲
        crs_epsg=32650  # UTM Zone 50N
    )
    # 根据类型获取所有相关类型的飞机信息
    aircrafts = get_all_aircrafts()
    # 根据所有符合条件的飞机查询对应的轨迹信息
    for aircraft in aircrafts:
        icao = aircraft[0]
        reg_id = aircraft[1]
        print(f"分析飞机: {icao}")
        trace_dict = get_aircraft_trace(reg_id)
        trajectory_data = pd.DataFrame(trace_dict, columns=['latitude', 'longitude', 'timestamp'])
        # 分析轨迹
        results = monitor.analyze_trajectory(trajectory_data)
        # 添加对 crossing_events 的打印
        merged_events = []  # 存储合并后的事件
        current_event = None  # 当前正在合并的事件

        for event in results['crossing_events']:
            # 如果是第一个事件，或当前事件方向与之前的相同
            if current_event is None or event['direction'] == current_event['direction']:
                # 如果是第一个事件，初始化current_event
                if current_event is None:
                    current_event = {
                        'start_time': event['time'],
                        'end_time': event['time'],
                        'direction': event['direction'],
                        'start_point': event['point_before'],
                        'end_point': event['point_after'],
                        'events': [event]
                    }
                else:
                    # 更新合并事件的结束时间和终点坐标
                    current_event['end_time'] = event['time']
                    current_event['end_point'] = event['point_after']
                    current_event['events'].append(event)
            else:
                # 方向改变时，将当前合并事件存入列表，并重置current_event
                merged_events.append(current_event)
                current_event = {
                    'start_time': event['time'],
                    'end_time': event['time'],
                    'direction': event['direction'],
                    'start_point': event['point_before'],
                    'end_point': event['point_after'],
                    'events': [event]
                }

        # 将最后一个合并事件存入列表
        if current_event:
            merged_events.append(current_event)
        print("\n抵近事件详情:")
        # 打印合并后的事件
        print(f"  包含事件数: {len(merged_events)}")
        for merged_event in merged_events:
            if merged_event['direction'] == 'inbound':
                direction = '抵近'
                set_result_to_mysql(reg_id, icao, merged_event)
            # direction = "抵近" if merged_event['direction'] == 'inbound' else "远离"
            # set_result_to_mysql(reg_id, icao, merged_event)
            print()  # 空行分隔不同合并事件

        # 可视化结果
        # monitor.visualize_results(trajectory_data, results, save_path="border_analysis.png")
